# -*- coding:utf-8 -*-
#! /bin/python

import os,sys
import hashlib,io
import my_log
import json
import ProgressStatus

def log(str):
    print("%s" % (str), end="")


class Node(object):

    def __init__(self, name=""):
        self.name = name
        self.dir = True
        self.child_node = {}
        self.data = ""

    def add_sub_dir(self, name):
        if name not in self.child_node.keys():
            self.child_node[name] = Node(name)
            self.child_node[name].child_node[".."] = self
            self.child_node[name].dir = True
        return self.child_node[name]

    def add_sub_file(self, name):
        if name not in self.child_node.keys():
            self.child_node[name] = Node(name)
            self.child_node[name].child_node[".."] = self
            self.child_node[name].dir = False
        return self.child_node[name]

    def is_dir(self):
        return self.dir

    def get_parent_node(self):
        #assert ".." in self.child_node.keys()
        return self.child_node.get("..")

    def get_name(self):
        return self.name

    def get_child_node(self,name):
        return self.child_node.get(name,None)

    
    def get_full_path(self):
        paths = [self.get_name()]
        _node = self
        while True:
            _node = _node.get_parent_node()
            if _node != None:
                paths.append(_node.get_name())
            else:
                break
        paths.reverse()
        path = ""
        paths = paths[1:] # remove "root"
        for p in paths:
            #path = os.path.join(path,p)
            path = path + "/" + p
        path = path[1:]  # remove the beginning of "/"
        if self.is_dir():
            path += "/"
        return path

    def get_child_names(self):
        return self.child_node.keys()

    def set_data(self,data=""):
        self.data = data

    def get_data(self):
        return self.data


# useless
class FilteTreeEncoder(json.JSONEncoder):
    def NextNode(self,node):
        if node.dir == False:
            return [node.data]
        c = {}
        n = [node.data,c]
        for k in node.child_node.keys():
            if k!= "..":
                c[k] = self.NextNode(node.child_node[k])
        return n

    def default(self, obj):
        if isinstance(obj,Node) == False:
            return json.JSONDecoder.default(self,obj)
        return self.NextNode(obj)


class FileTree():
    def __init__(self):
        self.root = Node("root")

    @staticmethod
    def split_path(path):
        names = []
        path = path.replace("\\\\", "\\")
        path = path.replace("//", "/")
        names = path.split("/")
        # s = os.path.split(path)
        # while s[1] != "":
        #     names.append(s[1])
        #     s = os.path.split(s[0])
        # names.append(s[0])
        # names.reverse()
        return names
    #"/" "{" "}" "," are illegal char in attributes
    #path="/dd/ss/dd" dd is a file
    #path="/dd/ss/dd/" dd is a dir

    def apply_path(self, path, attributes=""):
        paths = FileTree.split_path(os.path.dirname(path))
        name = os.path.basename(path)
        _file_node = self.root
        for p in paths:
            _file_node = _file_node.add_sub_dir(p)
        if name != "":
            _file_node = _file_node.add_sub_file(name)
        _file_node.set_data(attributes)
        return _file_node

    def get_node(self, path):
        if path == "":
            return self.root
        #path = os.path.normpath(path)
        paths = FileTree.split_path(os.path.dirname(path))
        name = os.path.basename(path)
        _file_node = self.root
        for p in paths:
            _file_child_node = _file_node.get_child_node(p)
            if _file_child_node == None:
                return None
            _file_node = _file_child_node
        if name != "":
            _file_node = _file_node.get_child_node(name)
        return _file_node

    def del_node(self, path):
        _node = self.get_node(path)
        if _node is None:
            return
        file_name = _node.get_name()
        p_node = _node.get_parent_node()
        p_node.child_node.pop(file_name)
        pass

    def load(self, _str=""):
        #print(_str)
        #_str = _str.decode("utf-8")
        if _str == "":
            return
        ProgressStatus.add_workload(len(_str))

        def get_item(__str=u"", i=0, end=[]):
            if len(__str)-i == 0:
                return u"",i
            j = i
            while True:
                c = __str[j]
                if len(__str) <= (j+1) or (c in end):
                    break
                j += 1
            return __str[i:j], j

        def parse_node(__str=u"",i=0):
            ProgressStatus.process(len(__str) - i)

            n = Node("")
            if len(__str) - i <= 0:
                return n, i  # name,Node,other_str
            n.name, i = get_item(__str,i, end=['/'])
            assert len(__str)- i > 0 and __str[i] == '/'
            i+=1  # consume '/'
            n.data, i = get_item(__str, i, end=['{', '}', ','])
            if len(__str)- i > 1 and __str[i] == '{':
                i+=1  # consume '{'
                n.dir = True
                while True:
                    _n, i = parse_node(__str,i)
                    _n.child_node[".."] = n
                    n.child_node[_n.name] = _n
                    assert len(__str)-i > 0
                    if __str[i] == '}':
                        break
                    else:
                        assert __str[i] == ','
                        i+=1  # consume ','
                i+=1  # consume '}'
            else:
                n.dir = False
            return n, i

        self.root, i = parse_node(_str, i=0)
        ProgressStatus.process(len(_str) - i)
        assert self.root.name == u'root'

        # this is a trick, "/" as seperator, so the root name need to be converted to ""
        # if "" in self.root.child_node.keys():
        #     self.root.child_node[""].name = "/"
        #     self.root.child_node["/"] = self.root.child_node[""]
        #     del(self.root.child_node[""])

    def dump(self):
        #return FileTree.__dump_json(self,self.root,1)
        import platform
        # this is a trick, "/" as seperator, so the root name need to be converted to ""
        # if "/" in self.root.child_node.keys():
        #     self.root.child_node["/"].name = ""
        #ret = FileTree.__dump(self, self.root, 1).encode("utf-8")
        ret = FileTree.__dump(self, self.root, 1)
        # if "/" in self.root.child_node.keys():
        #     self.root.child_node["/"].name = "/"
        return ret

    def __dump(self,node,deep):
        ret = ""
        #for i in range(1,deep):
        #    ret += " "
        ret = ret + node.name + "/" + node.data
        if node.is_dir():
            #ret = ret + ":"
            #ret = ret + ":\n"
            #for i in range(1,deep):
            #    ret += " "
            ret = ret + "{"
            for k in node.child_node.keys():
                if k != "..":
                    ret = ret + FileTree.__dump(self,node.child_node[k],deep+1) + ","
            if len(node.child_node) != 0:
                ret = ret[:-1]
            #ret = ret + "\n"
            #for i in range(1,deep):
            #    ret += " "
            ret = ret + "}"
        
        return ret

    #useless
    def __dump_json(self, node, deep):
        #json.dumps(node, default=FilteTreeEncoder)
        d = FilteTreeEncoder().encode(node)
        my_log.debug(d)
        #my_log.debug(json.dumps(node,cls = FilteTreeEncoder))
        #node.name
        # if node.is_dir():
        #
        #     for k in node.child_node.keys():
        #         if k != "..":
        #             FileTree.__dump(self, node.child_node[k], deep + 1) + ","

    #
    #return list of node
    def get_leaf_nodes(self):
        node_list = []

        def iter_node(_node = Node()):
            if _node == None:
                return
            if len(_node.child_node) <= 1:
                node_list.append(_node)
            else:
                for n in _node.child_node.keys():
                    if n == "..":
                        continue
                    iter_node(_node.child_node[n])
        for n in self.root.child_node.keys():
            if n == "..":
                continue
            iter_node(self.root.child_node[n])
        return node_list
